package oakclub.thrift.impl;

import oakclub.background.SendChatMessageBackground;
import oakclub.entity.*;
import oakclub.global.Container;
import oakclub.global.Context;
import oakclub.service.*;
import oakclub.thrift.service.API;
import oakclub.thrift.service.Device;
import oakclub.thrift.service.Target;
import oakclub.thrift.service.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class APIImpl implements API.Iface
{
    protected final Logger logger = LoggerFactory.getLogger(APIImpl.class);

    protected interface IExecute
    {
        public void execute(long userId, ResponseEntity response, Object... params) throws Exception;
    }

    protected String execute(User user, IExecute f, Object ... params)
    {
        ResponseEntity response = new ResponseEntity(ResponseEntity.ErrorCode.FAIL);

        // set context
        Context.set(new ContextEntity(user.platformId, user.fbToken, user.ipAddress));

        // auth fb_token
        AuthService userSerivce = (AuthService) Container.getComponent(AuthService.class);
        long userId = 0;
        try
        {
            userId = userSerivce.authToken();
        }
        catch(Exception e)
        {
            response.setMessage(e.getMessage());
            return response.toJson();
        }

        // login
        try
        {
            f.execute(userId, response, params);
        }
        catch(Exception e)
        {
            this.logger.warn("execute failed", e);

            response.setMessage(e.getMessage());
            return response.toJson();
        }

        // response
        response.setErrorCode(ResponseEntity.ErrorCode.SUCCESS);
        return response.toJson();
    }

    public String login(User user, Device device)
    {
        this.logger.info("login API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                // params
                Device device = (Device) params[0];

                // login
                UserService userService = (UserService) Container.getComponent(UserService.class);
                UserEntity userEntity = userService.login(userId, device.deviceName, device.osVersion, device.deviceToken);

                // parse
                Map<String, Object> user = new HashMap<>();
                user.put("user_id", userEntity.getId());
                user.put("profile_id", userEntity.getProfileId());
                user.put("name", userEntity.getDisplayName());
                user.put("avatar", userEntity.getAvatar().getUrl());
                user.put("birthday", userEntity.getBirthday());
                user.put("gender", userEntity.getGender().getId());
                user.put("interested_in", userEntity.getInterestedIn().getId());
                user.put("replationship", userEntity.getRelationship().getId());
                user.put("ethnicity", userEntity.getEthnicity().getId());
                user.put("is_new_user", userEntity.isNewUser());
                user.put("is_finished_register", userEntity.isFinishedRegister());
                user.put("is_private", userEntity.isPrivate());
                user.put("is_enabled", userEntity.isEnabled());
                user.put("is_star", userEntity.isStar());
                user.put("is_approved", userEntity.isApproved());
                user.put("is_vip", userEntity.isVip());
                user.put("created_time", userEntity.getCreatedTime());
                user.put("username", userEntity.getUsername());
                user.put("email", userEntity.getEmail());
                user.put("about_me", userEntity.getAboutMe());
                user.put("weight", userEntity.getWeight());
                user.put("height", userEntity.getHeight());
                user.put("last_login", userEntity.getLastLogin());
                user.put("work", 59);
                user.put("school", "");
                user.put("video", userEntity.getVideo().getUrl());
                user.put("num_viewed", userEntity.getNumViewed());
                user.put("num_liked", userEntity.getNumLiked());
                user.put("languages", new ArrayList<>());
                user.put("verification", new HashMap<>());
                user.put("location", new HashMap<>());
                user.put("xmpp", new HashMap<>());
                user.put("photos", new ArrayList<>());

                List<LanguageEntity> languageEntities = userEntity.getLanguages();
                ArrayList<Integer> languages = (ArrayList<Integer>) user.get("languages");
                for(LanguageEntity languageEntity : languageEntities)
                {
                    languages.add(languageEntity.getId());
                }

                VerificationEntity verificationEntity = userEntity.getVerification();
                HashMap<String, Object> verification = (HashMap<String, Object>) user.get("verification");
                verification.put("is_verified", verificationEntity.isVerified());
                verification.put("is_forced", verificationEntity.isForced());
                verification.put("is_skipped", verificationEntity.isSkipped());

                LocationEntity locationEntity = userEntity.getLocation();
                HashMap<String, Object> location = (HashMap<String, Object>) user.get("location");
                location.put("latitude", locationEntity.getLatitude());
                location.put("longitude", locationEntity.getLongitude());
                location.put("city", locationEntity.getCity().getName());
                location.put("country", locationEntity.getCity().getCountry().getName());

                XmppEntity xmppEntity = userEntity.getXmpp();
                HashMap<String, Object> xmpp = (HashMap<String, Object>) user.get("xmpp");
                xmpp.put("username", xmppEntity.getUsername());
                xmpp.put("password", xmppEntity.getPassword());

                List<SchoolEntity> schoolEntities = userEntity.getSchools();
                if(schoolEntities != null && !schoolEntities.isEmpty())
                {
                    user.put("school", schoolEntities.get(0).getName());
                }

                List<PhotoEntity> photoEntities = userEntity.getPhotos();
                ArrayList<Map<String, Object>> photos = (ArrayList<Map<String, Object>>) user.get("photos");
                for(PhotoEntity photoEntity : photoEntities)
                {
                    Map<String, Object> photo = new HashMap<>();
                    photo.put("id", photoEntity.getId());
                    photo.put("url", photoEntity.getUrl());
                    photo.put("is_avatar", photoEntity.isAvatar());
                    photos.add(photo);
                }

                response.put("user_info", user);
            }
        }, device);
    }

    public String ping(User user)
    {
        this.logger.info("ping API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                ActivityService activityService = (ActivityService) Container.getComponent(ActivityService.class);
                activityService.setOnline(userId);
            }
        });
    }

    public String addRoster(User user, Target target)
    {
        this.logger.info("addRoster API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                Target target = (Target) params[0];
                long targetId = UserService.toUserId(target.profileId);

                ChatService chatService = (ChatService) Container.getComponent(ChatService.class);
                chatService.addRoster(userId, targetId);
            }
        }, target);
    }

    public String getChatList(User user)
    {
        this.logger.info("getChatList API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                ChatService chatService = (ChatService) Container.getComponent(ChatService.class);
                List<RosterEntity> rosterEntities = chatService.getChatList(userId);

                List<Map<String, Object>> rosters = new ArrayList<>();
                for(RosterEntity rosterEntity : rosterEntities)
                {
                    UserEntity targetEntity = rosterEntity.getTarget();
                    Map<String, Object> roster = new HashMap<>();
                    roster.put("name", targetEntity.getDisplayName());
                    roster.put("profile_id", targetEntity.getProfileId());
                    roster.put("avatar", targetEntity.getAvatar().getUrl());
                    roster.put("birthday", targetEntity.getBirthday());
                    roster.put("xmpp", new HashMap<>());
                    roster.put("is_vip", targetEntity.isVip());
                    roster.put("unread_num", rosterEntity.getUnreadNum());
                    roster.put("last_message", new HashMap<>());
                    roster.put("last_active_time", rosterEntity.getLastActiveTime());
                    roster.put("mutual_match", new HashMap<>());
                    rosters.add(roster);

                    Map<String, Object> xmpp = (Map<String, Object>) roster.get("xmpp");
                    xmpp.put("username", targetEntity.getXmpp().getUsername());

                    Map<String, Object> lastMessage = (Map<String, Object>) roster.get("last_message");
                    lastMessage.put("message", rosterEntity.getLastMessage());
                    lastMessage.put("time", rosterEntity.getLastMessageTime());

                    MutualMatchEntity mutualMatchEntity = rosterEntity.getMutualMatch();
                    Map<String, Object> mutualMatch = (Map<String, Object>) roster.get("mutual_match");
                    mutualMatch.put("is_matched", mutualMatchEntity.isMatched());
                    mutualMatch.put("time", mutualMatchEntity.getMatchTime());
                    mutualMatch.put("chat_flag", mutualMatchEntity.getChatFlag());
                }

                response.put("rosters", rosters);
            }
        });
    }

    public String sendChatMessage(User user, Target target, String message)
    {
        this.logger.info("sendChatMessage API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                Target target = (Target) params[0];
                long targetId = UserService.toUserId(target.profileId);
                String message = (String) params[1];

                GearmanService gearmanService = (GearmanService) Container.getComponent(GearmanService.class);
                gearmanService.submitBackground(SendChatMessageBackground.class, new BackgroundEntity("user_id", userId, "target_id", targetId, "message", message));
            }
        }, target, message);
    }

    public String readChatMessage(User user, Target target)
    {
        this.logger.info("readMessage API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                Target target = (Target) params[0];
                long targetId = UserService.toUserId(target.profileId);

                ChatService chatService = (ChatService) Container.getComponent(ChatService.class);
                chatService.readMessage(userId, targetId);
            }
        }, target);
    }

    public String getChatHistory(User user, Target target)
    {
        this.logger.info("getChatHistory API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                Target target = (Target) params[0];
                long targetId = UserService.toUserId(target.profileId);

                ChatService chatService = (ChatService) Container.getComponent(ChatService.class);
                List<MessageEntity> entities = chatService.getHistory(userId, targetId);

                List<Map<String, Object>> messages = new ArrayList<>();
                for(MessageEntity entity : entities)
                {
                    Map<String, Object> message = new HashMap<>();
                    message.put("from", entity.getUser().getProfileId());
                    message.put("to", entity.getTarget().getProfileId());
                    message.put("time", entity.getTime());
                    message.put("content", entity.getContent());

                    messages.add(message);
                }

                response.put("messages", messages);
            }
        }, target);
    }

    public String setLocale(User user, String locale)
    {
        this.logger.info("setLocale API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                String locale = (String) params[0];

                UserService userService = (UserService) Container.getComponent(UserService.class);
                userService.setLocale(userId, locale);
            }
        }, locale);
    }

    public String blockUser(User user, Target target)
    {
        this.logger.info("blockUser API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                Target target = (Target) params[0];
                long targetId = UserService.toUserId(target.profileId);

                BlockService blockService = (BlockService) Container.getComponent(BlockService.class);
                blockService.blockUser(userId, targetId);
            }
        }, target);
    }

    public String unblockUser(User user, Target target)
    {
        this.logger.info("unblockUser API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                Target target = (Target) params[0];
                long targetId = UserService.toUserId(target.profileId);

                BlockService blockService = (BlockService) Container.getComponent(BlockService.class);
                blockService.unblockUser(userId, targetId);
            }
        }, target);
    }

    public String verifyUser(User user)
    {
        this.logger.info("verifyUser API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                UserService userService = (UserService) Container.getComponent(UserService.class);
                userService.verify(userId);
            }
        });
    }

    public String skipUserVerification(User user)
    {
        this.logger.info("skipUserVerification API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                UserService userService = (UserService) Container.getComponent(UserService.class);
                userService.skipVerification(userId);
            }
        });
    }

    public String reportUser(User user, Target target, String content)
    {
        this.logger.info("reportUser API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                Target target = (Target) params[0];
                long targetId = UserService.toUserId(target.profileId);
                String content = (String) params[1];

                AdminQueueService adminQueueService = (AdminQueueService) Container.getComponent(AdminQueueService.class);
                adminQueueService.addItem(targetId, AdminQueueService.ItemStatus.REPORT, userId, content);
            }
        }, target, content);
    }

    public String viewMutualMatch(User user, Target target)
    {
        this.logger.info("reportUser API");

        return this.execute(user, new IExecute()
        {
            @Override
            public void execute(long userId, ResponseEntity response, Object... params) throws Exception
            {
                Target target = (Target) params[0];
                long targetId = UserService.toUserId(target.profileId);

                MutualMatchService mutualMatchService = (MutualMatchService) Container.getComponent(MutualMatchService.class);
                mutualMatchService.view(userId, targetId);
            }
        }, target);
    }
}
